package com.gzx.plugin.tjzy.modular.repair.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.aliyun.oss.ServiceException;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gzx.plugin.tjzy.modular.repair.bo.*;
import com.gzx.plugin.tjzy.modular.repair.constant.RepairNumberConstant;
import com.gzx.plugin.tjzy.modular.repair.entity.GzxRepairPhoneNumber;
import com.gzx.plugin.tjzy.modular.repair.entity.GzxRepairPhoneNumberDetail;
import com.gzx.plugin.tjzy.modular.repair.mapper.GzxRepairPhoneNumberDetailMapper;
import com.gzx.plugin.tjzy.modular.repair.mapper.GzxRepairPhoneNumberMapper;
import com.gzx.plugin.tjzy.modular.repair.param.GzxRepairPhoneNumberPageParam;
import com.gzx.plugin.tjzy.modular.repair.service.GzxRepairPhoneNumberService;
import com.gzx.plugin.tjzy.modular.repair.utils.CipherUtil;
import com.gzx.plugin.tjzy.modular.repair.utils.RandomStringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.common.util.CommonExcelUtil;
import vip.xiaonuo.common.util.CommonHttpUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 失联修复
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class GzxRepairPhoneNumberServiceImpl extends ServiceImpl<GzxRepairPhoneNumberMapper, GzxRepairPhoneNumber> implements GzxRepairPhoneNumberService {

    private final GzxRepairPhoneNumberMapper gzxRepairPhonenumberMapper;

    private final GzxRepairPhoneNumberDetailMapper gzxRepairPhonenumberDetailMapper;

    @Value("${repair.repairUrl}")
    private String repairUrl;

    //联通号码池，每次绑定的时候随机选一个
    @Value("${repair.ltPool}")
    private String ltPool;

    //线路池，绑定的时候作为主叫号码
    @Value("${repair.linePool}")
    private String linePool;

    @Override
    @DS("tjzy")
    public Page<GzxRepairPhoneNumber> page(GzxRepairPhoneNumberPageParam gzxRepairPhonenumberPageParam) {
        QueryWrapper<GzxRepairPhoneNumber> queryWrapper = new QueryWrapper<GzxRepairPhoneNumber>().checkSqlInjection();
        if (ObjectUtil.isNotEmpty(gzxRepairPhonenumberPageParam.getName())) {
            queryWrapper.lambda().like(GzxRepairPhoneNumber::getName, gzxRepairPhonenumberPageParam.getName());
        }
        if (ObjectUtil.isNotEmpty(gzxRepairPhonenumberPageParam.getStatus())) {
            queryWrapper.lambda().eq(GzxRepairPhoneNumber::getStatus, gzxRepairPhonenumberPageParam.getStatus());
        }
        if (ObjectUtil.isNotEmpty(gzxRepairPhonenumberPageParam.getCreateNickName())) {
            queryWrapper.lambda().like(GzxRepairPhoneNumber::getCreateNickName, gzxRepairPhonenumberPageParam.getCreateNickName());
        }
        if (ObjectUtil.isAllNotEmpty(gzxRepairPhonenumberPageParam.getSortField(), gzxRepairPhonenumberPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(gzxRepairPhonenumberPageParam.getSortOrder());
            queryWrapper.orderBy(true, gzxRepairPhonenumberPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    CharSequenceUtil.toUnderlineCase(gzxRepairPhonenumberPageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByDesc(GzxRepairPhoneNumber::getId);
        }
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    @Override
    @DS("tjzy")
    public void delete(long id) {
        // 执行删除
        super.removeById(id);
    }

    /**
     * 查询出详情信息
     */
    @Override
    @DS("tjzy")
    public List<GzxRepairPhoneNumberDetail> getDetailList(int id) {
        LambdaQueryWrapper<GzxRepairPhoneNumberDetail> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(GzxRepairPhoneNumberDetail::getRepairBatchId, id);
        return gzxRepairPhonenumberDetailMapper.selectList(lambdaQueryWrapper);
    }

    /**
     * 导入修复名单
     */
    @Override
    @DSTransactional(rollbackFor = Exception.class)
    @DS("tjzy")
    public void importExcel(MultipartFile file) throws IOException {
        List<GzxRepairPhoneNumberDetail> excelResultList = CommonExcelUtil.importExcel(file, GzxRepairPhoneNumberDetail.class);
        if (CollUtil.isEmpty(excelResultList)) {
            throw new ServiceException("Excel为空");
        }
        GzxRepairPhoneNumber gzxRepairPhonenumber = new GzxRepairPhoneNumber();
        gzxRepairPhonenumber.setName(RandomStringUtil.generateRandomString(20));
        gzxRepairPhonenumber.setCreateNickName(StpLoginUserUtil.getLoginUser().getName());
        gzxRepairPhonenumber.setCreateDept(Long.parseLong(StpLoginUserUtil.getLoginUser().getOrgId()));
        gzxRepairPhonenumberMapper.insert(gzxRepairPhonenumber);

        //查询刚才入库那条数据的id
        LambdaQueryWrapper<GzxRepairPhoneNumber> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(GzxRepairPhoneNumber::getId);
        //获取名字
        wrapper.eq(GzxRepairPhoneNumber::getCreateNickName, StpLoginUserUtil.getLoginUser().getName());
        gzxRepairPhonenumber = gzxRepairPhonenumberMapper.selectList(wrapper).getFirst();
        String id = gzxRepairPhonenumber.getId();
        for (GzxRepairPhoneNumberDetail entity : excelResultList) {
            entity.setRepairBatchId(id);
            try {
                entity.setIdcard(CipherUtil.encryptSha256(entity.getIdcard()));
            } catch (Exception e) {
                log.error("导入修复名单异常：", e);
            }
            entity.setCreateBy(String.valueOf(StpLoginUserUtil.getLoginUser().getId()));
        }
        gzxRepairPhonenumberDetailMapper.insertBatch(excelResultList);
    }

    //开始修复
    @Override
    @DS("tjzy")
    public void repairNumber(int id) {
        //获取项目批次号
        GzxRepairPhoneNumber repairPhone = gzxRepairPhonenumberMapper.selectById((long) id);
        //获取当前ID的所有的detail
        LambdaQueryWrapper<GzxRepairPhoneNumberDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GzxRepairPhoneNumberDetail::getRepairBatchId, id);
        List<GzxRepairPhoneNumberDetail> list = gzxRepairPhonenumberDetailMapper.selectList(wrapper);

        //内层手机号，身份证等报文
        List<GzxRequestItemBo> item = new ArrayList<>();
        for (GzxRepairPhoneNumberDetail entity : list) {
            item.add(new GzxRequestItemBo(entity.getName(), entity.getIdcard(), entity.getCallingNumber(), RandomStringUtil.generateRandomString(20)));
        }
        //中间层报文
        GzxDataBo data = new GzxDataBo();
        data.setMaskModel(RepairNumberConstant.MASK_MODEL_ONE);
        data.setSource("");
        data.setData(item);

        //最外层报文
        GzxRequestDataBo dataBo = new GzxRequestDataBo();
        dataBo.setType(RepairNumberConstant.UPLOAD_TYPE);
        dataBo.setData(data);

        //调用修复接口（电信没开通，为什么要单独修复移动或者联通，因为一个人可能同时在三个运营商都有手机号，如果匹配三次就是收费三次）
        dataBo.setOperator(RepairNumberConstant.OPERATOR_YD);
        String ydRsp = CommonHttpUtil.post(repairUrl, null, JSON.toJSONString(dataBo), "移动失联修复");
        log.info("开始失联修复-移动返回结果 {} ", ydRsp);
        if (ObjectUtil.isEmpty(ydRsp)) {
            log.warn("调用修复接口移动返回为空");
        }

        com.alibaba.fastjson2.JSONObject yd = JSON.parseObject(ydRsp);
        com.alibaba.fastjson2.JSONObject ydData = JSON.parseObject(yd.getString("data"));
        if (ObjectUtil.isEmpty(ydData)) {
            log.warn("移动接口返回数据为空 {} ", yd);
        } else {
            repairPhone.setYdBatchNumber(ydData.getString("operateBatchNo"));
        }

        //联通
        dataBo.setOperator(RepairNumberConstant.OPERATOR_LT);
        String ltRsp = CommonHttpUtil.post(repairUrl, null, JSON.toJSONString(dataBo), "联通失联修复");
        log.info("开始失联修复-联通返回结果 {} ", ltRsp);
        if (ObjectUtil.isEmpty(ltRsp)) {
            log.warn("调用修复接口联通返回为空");
        }

        com.alibaba.fastjson2.JSONObject lt = JSON.parseObject(ltRsp);
        com.alibaba.fastjson2.JSONObject ltData = JSON.parseObject(lt.getString("data"));
        if (ObjectUtil.isEmpty(ltData)) {
            log.warn("联通接口返回数据为空 {} ", lt);
        } else {
            repairPhone.setLtBatchNumber(ltData.getString("operateBatchNo"));
        }

        //接口返回的批次号更新到 repairPhone 中
        gzxRepairPhonenumberMapper.updateById(repairPhone);
    }

    //加载修复结果
    @DS("tjzy")
    @Override
    @DSTransactional(rollbackFor = Exception.class)
    public void loadRepairResult(Integer id) {
        //获取项目批次号
        GzxRepairPhoneNumber repairPhone = gzxRepairPhonenumberMapper.selectById((long) id);
        //获取当前ID的所有的detail
        LambdaQueryWrapper<GzxRepairPhoneNumberDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GzxRepairPhoneNumberDetail::getRepairBatchId, id);
        List<GzxRepairPhoneNumberDetail> detailList = gzxRepairPhonenumberDetailMapper.selectList(wrapper);
        //封装报文
        GzxRequestDataBo dataBo = new GzxRequestDataBo();
        GzxDataBo data = new GzxDataBo();
        dataBo.setType(RepairNumberConstant.REPAIR_RESULT);
        //移动批次号
        dataBo.setOperator(RepairNumberConstant.OPERATOR_YD);
        data.setOperateBatchNo(repairPhone.getYdBatchNumber());
        dataBo.setData(data);
        //获取移动结果
        com.alibaba.fastjson2.JSONObject ydData = loadResult(dataBo, detailList, RepairNumberConstant.OPERATOR_YD);
        log.info("开始加载修复结果-移动返回结果 {} ", ydData);

        //联通批次号
        dataBo.setOperator(RepairNumberConstant.OPERATOR_LT);
        data.setOperateBatchNo(repairPhone.getLtBatchNumber());
        dataBo.setData(data);
        //调用修复结果接口-联通：
        com.alibaba.fastjson2.JSONObject ltData = loadResult(dataBo, detailList, RepairNumberConstant.OPERATOR_LT);
        log.info("开始加载修复结果-联通返回结果 {} ", ltData);

        // 批次修复状态：1:待修复 2:修复中 3:修复完成 并且有成功修复的数据时,matchResult有值 4:修复失败 failCode,failMsg有值
        int ydBatchStatus = 0;
        int ltBatchStatus = 0;
        if (ydData != null) {
            ydBatchStatus = ydData.getIntValue("batchStatus");
        }
        if (ltData != null) {
            ltBatchStatus = ltData.getIntValue("batchStatus");
        }
        if (ydBatchStatus == 2 || ltBatchStatus == 2) {
            //状态：0已上传未进行修复，1表示已经进行修复中，2表示修复成功，3表示修复失败
            repairPhone.setStatus(1);
        } else if (ydBatchStatus == 3 || ltBatchStatus == 3) {
            //状态：0已上传未进行修复，1表示已经进行修复中，2表示修复成功，3表示修复失败
            repairPhone.setStatus(2);
        } else if (ydBatchStatus == 4 || ltBatchStatus == 4) {
            //状态：0已上传未进行修复，1表示已经进行修复中，2表示修复成功，3表示修复失败
            repairPhone.setStatus(3);
        }
        //修改批次主表
        gzxRepairPhonenumberMapper.updateById(repairPhone);
        //修改批次子表
        gzxRepairPhonenumberDetailMapper.updateBatchById(detailList);
    }

    //移动获取修复结果
    private com.alibaba.fastjson2.JSONObject loadResult(GzxRequestDataBo dataBo, List<GzxRepairPhoneNumberDetail> detailList, int repairChannel) {
        //调用修复结果接口-移动：
        String rsp = CommonHttpUtil.post(repairUrl, null, JSON.toJSONString(dataBo), "获取修复结果");
        com.alibaba.fastjson2.JSONObject operate = JSON.parseObject(rsp);
        //0成功，其它失败，失败了跳出此方法，等其它运营商的修复结果
        if (!"0".equals(operate.getString("code"))) {
            return null;
        }
        com.alibaba.fastjson2.JSONObject data = JSON.parseObject(operate.getString("data"));

        List<GzxResponseMatchResult> matchResult = JSON.parseArray(data.getString("matchResult"), GzxResponseMatchResult.class);
        //移动
        for (GzxResponseMatchResult entity : matchResult) {
            List<GzxResponsePhoneList> phoneList = entity.getPhoneList();
            //修改复完成后成功状态，0未修复 1已修复
            if ("1".equals(entity.getRepairStatus())) {
                for (GzxRepairPhoneNumberDetail detail : detailList) {
                    //比较detail和修复的结果，如果身份证号相同，则把其它列放到detail中
                    if (entity.getIdCard().equals(detail.getIdcard())) {
                        for (GzxResponsePhoneList phone : phoneList) {
                            //移动有个区号，联通没有 areaCode
                            detail.setAreaCode(phone.getPhoneAreaCode());
                            detail.setNewPhoneNumber(phone.getPhoneSeqNo());
                            //运营商
                            detail.setOperate(repairChannel);
                            //绑定中间号的时候用
                            detail.setResultId(entity.getResultId());
                        }
                    }
                }
            }
        }
        return data;
    }

    @Override
    @DS("tjzy")
    public void repairLost() {
        //获取所有未修复的批次
        LambdaQueryWrapper<GzxRepairPhoneNumber> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GzxRepairPhoneNumber::getStatus, 2);
        List<GzxRepairPhoneNumber> list = gzxRepairPhonenumberMapper.selectList(wrapper);
        for (GzxRepairPhoneNumber phone : list) {
            //获取修复结果
            loadRepairResult(Integer.parseInt(phone.getId()));
            //修复之后看看状态是不是修复成功了
            GzxRepairPhoneNumber phoneNumber = gzxRepairPhonenumberMapper.selectById(phone.getId());
            //修复成功了
            if (phoneNumber.getStatus() == 2) {
                //获取批次下的详情数据
                LambdaQueryWrapper<GzxRepairPhoneNumberDetail> wrapperDetail = new LambdaQueryWrapper<>();
                wrapperDetail.eq(GzxRepairPhoneNumberDetail::getRepairBatchId, phoneNumber.getId());
                List<GzxRepairPhoneNumberDetail> detailList = gzxRepairPhonenumberDetailMapper.selectList(wrapperDetail);

                //从联通号码池获取telX
                String telX = RandomStringUtil.getRandomPhone(ltPool);

                for (GzxRepairPhoneNumberDetail detail : detailList) {
                    //如果已绑定则跳过
                    if (ObjectUtil.isNotEmpty(detail.getRepairedPhone())) {
                        continue;
                    }
                    GzxRequestDataBo dataBo = new GzxRequestDataBo();
                    GzxDataBo data = new GzxDataBo();
                    //通用参数
                    data.setMaskModel(RepairNumberConstant.MASK_MODEL_ONE);
                    data.setResultId(detail.getResultId());
                    data.setIdCard(detail.getIdcard());
                    data.setPhoneSeqNo(detail.getNewPhoneNumber());
                    dataBo.setType(RepairNumberConstant.BIND_VIRTUAL);
                    //主叫，外显先用同一个值
                    data.setSeatNumber(linePool);
                    data.setShowNumber(linePool);

                    //移动
                    if (RepairNumberConstant.OPERATOR_YD == detail.getOperate()) {
                        data.setOperateBatchNo(phoneNumber.getYdBatchNumber());
                        data.setPhoneAreaCode(detail.getAreaCode());
                        dataBo.setOperator(RepairNumberConstant.OPERATOR_YD);
                        dataBo.setData(data);
                        getBindResult(detail, dataBo, "移动绑定中间号");
                    }

                    //联通
                    if (RepairNumberConstant.OPERATOR_LT == detail.getOperate()) {
                        data.setOperateBatchNo(phoneNumber.getLtBatchNumber());
                        dataBo.setOperator(RepairNumberConstant.OPERATOR_LT);
                        data.setTelX(telX);
                        dataBo.setData(data);
                        getBindResult(detail, dataBo, "联通绑定中间号");
                    }
                }
            }
        }
    }

    @DS("tjzy")
    private void getBindResult(GzxRepairPhoneNumberDetail detail, GzxRequestDataBo dataBo, String type) {
        //绑定虚拟号，每次拨打之前绑定会返回一个中间号
        String ydRsp = CommonHttpUtil.post(repairUrl, null, JSON.toJSONString(dataBo), type);
        com.alibaba.fastjson2.JSONObject operate = JSON.parseObject(ydRsp);
        //0成功，其它失败，失败了跳出此方法，等其它运营商的修复结果
        if (!"0".equals(operate.getString("code"))) {
            return;
        }
        com.alibaba.fastjson2.JSONObject data = JSON.parseObject(operate.getString("data"));
        if (ObjectUtil.isEmpty(data)) {
            return;
        }

        //telX是中间号
        detail.setTelX(data.getString("telX"));
        detail.setBindId(data.getString("bindId"));
        detail.setRepairedPhone(data.getString("telX"));
        //把绑定的中间号入库
        gzxRepairPhonenumberDetailMapper.updateById(detail);
    }
}